package com.project.common.core.utils.exportView.view;

import com.project.common.core.utils.exportView.convert.Convert;
import com.project.common.core.utils.file.FileUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * excel视图
 */
//public class ExcelView extends AbstractXlsxView {
public class ExcelView {

    /**
     * 日志类
     */
    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 文件名称
     */
    private String filename;

    /**
     * 表名称
     */
    private String sheetName;

    /**
     * 属性
     */
    private String[] properties;

    /**
     * 标题
     */
    private String[] titles;

    /**
     * 图片属性集合
     */
    private String[] pictures;

    /**
     * 列宽
     */
    private Integer[] widths;

    /**
     * 表体高度
     */
    private Float bodyHeight;

    /**
     * 数据
     */
    private Collection<?> data;

    /**
     * 附加内容
     */
    private String[] contents;

    /**
     * 数据转换map
     */
    private Map<String, Convert> convertMap = new HashMap<String, Convert>();

    /**
     * @param filename   文件名称
     * @param sheetName  表名称
     * @param properties 属性
     * @param titles     标题
     * @param widths     列宽
     * @param data       数据
     * @param contents   附加内容
     * @param convertMap 数据转化map
     */
    public ExcelView(String filename, String sheetName, String[] properties, String[] titles, Integer[] widths, Collection<?> data, String[] contents, Map<String, Convert> convertMap) {
        this.filename = filename;
        this.sheetName = sheetName;
        this.properties = properties;
        this.titles = titles;
        this.widths = widths;
        this.data = data;
        this.contents = contents;
        this.convertMap = MapUtils.isEmpty(convertMap) ? this.convertMap : convertMap;
    }

    /**
     * @param filename   文件名称
     * @param sheetName  表名称
     * @param properties 属性
     * @param titles     标题
     * @param pictures   图片属性
     * @param widths     列宽
     * @param bodyHeight 表体高度
     * @param data       数据
     * @param contents   附加内容
     * @param convertMap 数据转化map
     */
    public ExcelView(String filename, String sheetName, String[] properties, String[] titles, String[] pictures, Integer[] widths, Float bodyHeight, Collection<?> data, String[] contents, Map<String, Convert> convertMap) {
        this.filename = filename;
        this.sheetName = sheetName;
        this.properties = properties;
        this.titles = titles;
        this.pictures = pictures;
        this.widths = widths;
        this.bodyHeight = bodyHeight;
        this.data = data;
        this.contents = contents;
        this.convertMap = MapUtils.isEmpty(convertMap) ? this.convertMap : convertMap;
    }

    /**
     * @param properties 属性
     * @param titles     标题
     * @param data       数据
     * @param contents   附加内容
     */
    public ExcelView(String filename, String[] properties, String[] titles, Collection<?> data, String[] contents, Map<String, Convert> convertMap) {
        this.filename = filename;
        this.properties = properties;
        this.titles = titles;
        this.data = data;
        this.contents = contents;
        this.convertMap = MapUtils.isEmpty(convertMap) ? this.convertMap : convertMap;
    }

    /**
     * @param properties 属性
     * @param titles     标题
     * @param data       数据
     */
    public ExcelView(String filename, String[] properties, String[] titles, Collection<?> data, Map<String, Convert> convertMap) {
        this.filename = filename;
        this.properties = properties;
        this.titles = titles;
        this.data = data;
        this.convertMap = MapUtils.isEmpty(convertMap) ? this.convertMap : convertMap;
    }

    /**
     * @param properties 属性
     * @param data       数据
     */
    public ExcelView(String[] properties, Collection<?> data) {
        this.properties = properties;
        this.data = data;
    }

    //    @Override
    protected void buildExcelDocument(Map<String, Object> map, Workbook workbook, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        try {

            Assert.notEmpty(properties, "表格导出中属性为空");
            Sheet sheet;
            if (StringUtils.isNotEmpty(sheetName)) {
                sheet = workbook.createSheet(sheetName);
            } else {
                sheet = workbook.createSheet();
            }
            int rowNumber = 0;

            //创建表头
            if (titles != null && titles.length > 0) {
//                HSSFRow header = sheet.createRow(rowNumber);
                Row header = sheet.createRow(rowNumber);
                header.setHeight((short) 400);
                for (int i = 0; i < properties.length; i++) {
                    Cell cell = header.createCell(i);
                    CellStyle cellStyle = workbook.createCellStyle();
                    cellStyle.setFillForegroundColor(HSSFColor.LIGHT_CORNFLOWER_BLUE.index);
                    cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                    cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
                    cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
                    Font font = workbook.createFont();
                    font.setFontHeightInPoints((short) 11);
                    font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
                    cellStyle.setFont(font);
                    cell.setCellStyle(cellStyle);

                    if (i == 0) {
                        Drawing patriarch = sheet.createDrawingPatriarch();
                        Comment comment = patriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) 1, 1, (short) 4, 4));
                        comment.setString(new XSSFRichTextString("亿函科技公司版权所有"));
                        cell.setCellComment(comment);
                    }
                    if (titles.length > i && titles[i] != null) {
                        cell.setCellValue(titles[i]);
                    } else {
                        cell.setCellValue(properties[i]);
                    }
                    if (widths != null && widths.length > i && widths[i] != null) {
                        sheet.setColumnWidth(i, widths[i]);
                    } else {
                        sheet.autoSizeColumn(i);
                    }
                }
                rowNumber++;
            }

            //写入数据
            if (data != null) {
                String property;
                Convert convert;
                Drawing drawing = sheet.createDrawingPatriarch();
                for (Object item : data) {
                    Row row = sheet.createRow(rowNumber);
                    // 设置Excel表格高度(除标题以外)
                    if (this.bodyHeight != null) {
                        row.setHeightInPoints(this.bodyHeight);
                    }

                    for (int i = 0; i < properties.length; i++) {
                        Cell cell = row.createCell(i);
                        CellStyle cs = workbook.createCellStyle();
                        cs.setAlignment(CellStyle.ALIGN_CENTER); //水平居中
                        cs.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //垂直居中
                        cs.setWrapText(true); //设置自动换行
                        cell.setCellStyle(cs);

                        property = properties[i];
                        convert = convertMap.get(property);

                        String value = null;
                        if (item instanceof Map) {
                            Object val = ((Map) item).get(property);
                            value = val == null ? null : val.toString();
                        } else {
                            value = BeanUtils.getProperty(item, property);
                        }
                        if (convert != null) {
                            value = convert.convert(value);
                        }
                        cell.setCellValue(value);
                        if (convert == null) {
                            cell.setCellValue(BeanUtils.getProperty(item, property));
                        } else {
                            cell.setCellValue(convert.convert(BeanUtils.getProperty(item, property)));
                        }

                        if (rowNumber == 0 || rowNumber == 1) {
                            if (widths != null && widths.length > i && widths[i] != null) {
                                sheet.setColumnWidth(i, widths[i]);
                            } else {
                                sheet.autoSizeColumn(i);
                            }
                        }
                    }

                    // 处理图片
                    if (pictures != null) {
                        for (int j = 0; j < pictures.length; j++) {
                            property = pictures[j];
                            String value = null;
                            if (item instanceof Map) {
                                Object val = ((Map) item).get(property);
                                value = val == null ? null : val.toString();
                            } else {
                                value = BeanUtils.getProperty(item, property);
                            }
                            if (StringUtils.isNotBlank(value)) {

                                // 清空图片地址
                                row.getCell(properties.length - 1 + j).setCellValue("");

                                // 将图片服务器上的图片转成byte数组
                                InputStream is = FileUtil.remotePathToStream(value);
                                if (is != null) {
                                    byte[] data = IOUtils.toByteArray(is);
                                    // 写图片
                                    XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) (properties.length - 1 + j),
                                            row.getRowNum(), (short) (properties.length + j), row.getRowNum() + 1);
                                    drawing.createPicture(anchor, workbook.addPicture(data, XSSFWorkbook.PICTURE_TYPE_JPEG));
                                }
                            }
                        }
                    }

                    rowNumber++;
                }
            }

            //写入汇总信息
            if (contents != null && contents.length > 0) {
                rowNumber++;
                for (String content : contents) {
                    Row row = sheet.createRow(rowNumber);
                    Cell cell = row.createCell(0);
                    CellStyle cellStyle = workbook.createCellStyle();
                    Font font = workbook.createFont();
                    font.setColor(HSSFColor.GREY_50_PERCENT.index);
                    cellStyle.setFont(font);
                    cell.setCellStyle(cellStyle);
                    cell.setCellValue(content);
                    rowNumber++;
                }
            }

            httpServletResponse.setContentType("application/force-download");
            if (StringUtils.isNotEmpty(filename)) {
                httpServletResponse.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
            } else {
                httpServletResponse.setHeader("Content-disposition", "attachment");
            }
        } catch (Exception e) {
            log.error("\r\n ************ Excle导出工具类方法【buildExcelDocument】报错:{}", ExceptionUtils.getStackTrace(e));
        }
    }

    /**
     * 获取文件名称
     *
     * @return 文件名称
     */
    public String getFileName() {
        return filename;
    }

    /**
     * 设置文件名称
     *
     * @param filename 文件名称
     */
    public void setFileName(String filename) {
        this.filename = filename;
    }

    /**
     * 获取表名称
     *
     * @return 表名称
     */
    public String getSheetName() {
        return sheetName;
    }

    /**
     * 设置表名称
     *
     * @param sheetName 表名称
     */
    public void setSheetName(String sheetName) {
        this.sheetName = sheetName;
    }

    /**
     * 获取属性
     *
     * @return 属性
     */
    public String[] getProperties() {
        return properties;
    }

    /**
     * 设置属性
     *
     * @param properties 属性
     */
    public void setProperties(String[] properties) {
        this.properties = properties;
    }

    /**
     * 获取标题
     *
     * @return 标题
     */
    public String[] getTitles() {
        return titles;
    }

    /**
     * 设置标题
     *
     * @param titles 标题
     */
    public void setTitles(String[] titles) {
        this.titles = titles;
    }

    /**
     * 获取图片属性集合
     */
    public String[] getPictures() {
        return pictures;
    }

    /**
     * 设置图片属性集合
     */
    public void setPictures(String[] pictures) {
        this.pictures = pictures;
    }

    /**
     * 获取列宽
     *
     * @return 列宽
     */
    public Integer[] getWidths() {
        return widths;
    }

    /**
     * 设置列宽
     *
     * @param widths 列宽
     */
    public void setWidths(Integer[] widths) {
        this.widths = widths;
    }

    /**
     * 获取表体高度
     */
    public Float getBodyHeight() {
        return bodyHeight;
    }

    /**
     * 设置表体高度
     */
    public void setBodyHeight(Float bodyHeight) {
        this.bodyHeight = bodyHeight;
    }

    /**
     * 获取数据
     *
     * @return 数据
     */
    public Collection<?> getData() {
        return data;
    }

    /**
     * 设置数据
     *
     * @param data 数据
     */
    public void setData(Collection<?> data) {
        this.data = data;
    }

    /**
     * 获取附加内容
     *
     * @return 附加内容
     */
    public String[] getContents() {
        return contents;
    }

    /**
     * 设置附加内容
     *
     * @param contents 附加内容
     */
    public void setContents(String[] contents) {
        this.contents = contents;
    }

}
